home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / trckrect.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  21.3 KB  |  766 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE4_SEG
  14. #pragma code_seg(AFX_CORE4_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CRectTracker global state
  26.  
  27. // various GDI objects we need to draw
  28. AFX_STATIC_DATA HCURSOR _afxCursors[10] = { 0, };
  29. AFX_STATIC_DATA HBRUSH _afxHatchBrush = 0;
  30. AFX_STATIC_DATA HPEN _afxBlackDottedPen = 0;
  31. AFX_STATIC_DATA int _afxHandleSize = 0;
  32.  
  33. void AFX_CDECL AfxTrackerTerm()
  34. {
  35.     AfxDeleteObject((HGDIOBJ*)&_afxHatchBrush);
  36.     AfxDeleteObject((HGDIOBJ*)&_afxBlackDottedPen);
  37. }
  38. char _afxTrackerTerm = (char)atexit(&AfxTrackerTerm);
  39.  
  40. // the struct below is used to determine the qualities of a particular handle
  41. struct AFX_HANDLEINFO
  42. {
  43.     size_t nOffsetX;    // offset within RECT for X coordinate
  44.     size_t nOffsetY;    // offset within RECT for Y coordinate
  45.     int nCenterX;       // adjust X by Width()/2 * this number
  46.     int nCenterY;       // adjust Y by Height()/2 * this number
  47.     int nHandleX;       // adjust X by handle size * this number
  48.     int nHandleY;       // adjust Y by handle size * this number
  49.     int nInvertX;       // handle converts to this when X inverted
  50.     int nInvertY;       // handle converts to this when Y inverted
  51. };
  52.  
  53. // this array describes all 8 handles (clock-wise)
  54. AFX_STATIC_DATA const AFX_HANDLEINFO _afxHandleInfo[] =
  55. {
  56.     // corner handles (top-left, top-right, bottom-right, bottom-left
  57.     { offsetof(RECT, left), offsetof(RECT, top),        0, 0,  0,  0, 1, 3 },
  58.     { offsetof(RECT, right), offsetof(RECT, top),       0, 0, -1,  0, 0, 2 },
  59.     { offsetof(RECT, right), offsetof(RECT, bottom),    0, 0, -1, -1, 3, 1 },
  60.     { offsetof(RECT, left), offsetof(RECT, bottom),     0, 0,  0, -1, 2, 0 },
  61.  
  62.     // side handles (top, right, bottom, left)
  63.     { offsetof(RECT, left), offsetof(RECT, top),        1, 0,  0,  0, 4, 6 },
  64.     { offsetof(RECT, right), offsetof(RECT, top),       0, 1, -1,  0, 7, 5 },
  65.     { offsetof(RECT, left), offsetof(RECT, bottom),     1, 0,  0, -1, 6, 4 },
  66.     { offsetof(RECT, left), offsetof(RECT, top),        0, 1,  0,  0, 5, 7 }
  67. };
  68.  
  69. // the struct below gives us information on the layout of a RECT struct and
  70. //  the relationship between its members
  71. struct AFX_RECTINFO
  72. {
  73.     size_t nOffsetAcross;   // offset of opposite point (ie. left->right)
  74.     int nSignAcross;        // sign relative to that point (ie. add/subtract)
  75. };
  76.  
  77. // this array is indexed by the offset of the RECT member / sizeof(int)
  78. AFX_STATIC_DATA const AFX_RECTINFO _afxRectInfo[] =
  79. {
  80.     { offsetof(RECT, right), +1 },
  81.     { offsetof(RECT, bottom), +1 },
  82.     { offsetof(RECT, left), -1 },
  83.     { offsetof(RECT, top), -1 },
  84. };
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // CRectTracker intitialization
  88.  
  89. CRectTracker::CRectTracker(LPCRECT lpSrcRect, UINT nStyle)
  90. {
  91.     ASSERT(AfxIsValidAddress(lpSrcRect, sizeof(RECT), FALSE));
  92.  
  93.     Construct();
  94.     m_rect.CopyRect(lpSrcRect);
  95.     m_nStyle = nStyle;
  96. }
  97.  
  98. void CRectTracker::Construct()
  99. {
  100.     // do one-time initialization if necessary
  101.     AfxLockGlobals(CRIT_RECTTRACKER);
  102.     static BOOL bInitialized;
  103.     if (!bInitialized)
  104.     {
  105.         // sanity checks for assumptions we make in the code
  106.         ASSERT(sizeof(((RECT*)NULL)->left) == sizeof(int));
  107.         ASSERT(offsetof(RECT, top) > offsetof(RECT, left));
  108.         ASSERT(offsetof(RECT, right) > offsetof(RECT, top));
  109.         ASSERT(offsetof(RECT, bottom) > offsetof(RECT, right));
  110.  
  111.         if (_afxHatchBrush == NULL)
  112.         {
  113.             // create the hatch pattern + bitmap
  114.             WORD hatchPattern[8];
  115.             WORD wPattern = 0x1111;
  116.             for (int i = 0; i < 4; i++)
  117.             {
  118.                 hatchPattern[i] = wPattern;
  119.                 hatchPattern[i+4] = wPattern;
  120.                 wPattern <<= 1;
  121.             }
  122.             HBITMAP hatchBitmap = CreateBitmap(8, 8, 1, 1, &hatchPattern);
  123.             if (hatchBitmap == NULL)
  124.             {
  125.                 AfxUnlockGlobals(CRIT_RECTTRACKER);
  126.                 AfxThrowResourceException();
  127.             }
  128.  
  129.             // create black hatched brush
  130.             _afxHatchBrush = CreatePatternBrush(hatchBitmap);
  131.             DeleteObject(hatchBitmap);
  132.             if (_afxHatchBrush == NULL)
  133.             {
  134.                 AfxUnlockGlobals(CRIT_RECTTRACKER);
  135.                 AfxThrowResourceException();
  136.             }
  137.         }
  138.  
  139.         if (_afxBlackDottedPen == NULL)
  140.         {
  141.             // create black dotted pen
  142.             _afxBlackDottedPen = WCE_FCTN(CreatePen)(PS_DOT, 0, RGB(0, 0, 0));
  143.             if (_afxBlackDottedPen == NULL)
  144.             {
  145.                 AfxUnlockGlobals(CRIT_RECTTRACKER);
  146.                 AfxThrowResourceException();
  147.             }
  148.         }
  149.  
  150. #if !defined(_WIN32_WCE_NO_CURSOR)
  151.         // Note: all track cursors must live in same module
  152.         HINSTANCE hInst = AfxFindResourceHandle(
  153.             MAKEINTRESOURCE(AFX_IDC_TRACK4WAY), RT_GROUP_CURSOR);
  154.  
  155.         // initialize the cursor array
  156.         _afxCursors[0] = ::WCE_FCTN(LoadCursor)(hInst, MAKEINTRESOURCE(AFX_IDC_TRACKNWSE));
  157.         _afxCursors[1] = ::WCE_FCTN(LoadCursor)(hInst, MAKEINTRESOURCE(AFX_IDC_TRACKNESW));
  158.         _afxCursors[2] = _afxCursors[0];
  159.         _afxCursors[3] = _afxCursors[1];
  160.         _afxCursors[4] = ::WCE_FCTN(LoadCursor)(hInst, MAKEINTRESOURCE(AFX_IDC_TRACKNS));
  161.         _afxCursors[5] = ::WCE_FCTN(LoadCursor)(hInst, MAKEINTRESOURCE(AFX_IDC_TRACKWE));
  162.         _afxCursors[6] = _afxCursors[4];
  163.         _afxCursors[7] = _afxCursors[5];
  164.         _afxCursors[8] = ::WCE_FCTN(LoadCursor)(hInst, MAKEINTRESOURCE(AFX_IDC_TRACK4WAY));
  165.         _afxCursors[9] = ::WCE_FCTN(LoadCursor)(hInst, MAKEINTRESOURCE(AFX_IDC_MOVE4WAY));
  166. #endif // _WIN32_WCE_NO_CURSOR
  167.  
  168.         // get default handle size from Windows profile setting
  169. #if defined(_WIN32_WCE)
  170.         _afxHandleSize = 4;
  171. #else // _WIN32_WCE
  172.         static const TCHAR szWindows[] = _T("windows");
  173.         static const TCHAR szInplaceBorderWidth[] =
  174.             _T("oleinplaceborderwidth");
  175.         _afxHandleSize = GetProfileInt(szWindows, szInplaceBorderWidth, 4);
  176. #endif // _WIN32_WCE
  177.         bInitialized = TRUE;
  178.     }
  179.     AfxUnlockGlobals(CRIT_RECTTRACKER);
  180.  
  181.     m_nStyle = 0;
  182.     m_nHandleSize = _afxHandleSize;
  183.     m_sizeMin.cy = m_sizeMin.cx = m_nHandleSize*2;
  184.  
  185.     m_rectLast.SetRectEmpty();
  186.     m_sizeLast.cx = m_sizeLast.cy = 0;
  187.     m_bErase = FALSE;
  188.     m_bFinalErase =  FALSE;
  189. }
  190.  
  191. CRectTracker::~CRectTracker()
  192. {
  193. }
  194.  
  195. /////////////////////////////////////////////////////////////////////////////
  196. // CRectTracker operations
  197.  
  198. void CRectTracker::Draw(CDC* pDC) const
  199. {
  200.     // set initial DC state
  201.     VERIFY(pDC->SaveDC() != 0);
  202. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)  
  203.     pDC->SetMapMode(MM_TEXT);
  204.     pDC->SetViewportOrg(0, 0);
  205.     pDC->SetWindowOrg(0, 0);
  206. #endif // _WIN32_WCE_NO_GDITRANSFORM
  207.  
  208.     // get normalized rectangle
  209.     CRect rect = m_rect;
  210.     rect.NormalizeRect();
  211.  
  212.     CPen* pOldPen = NULL;
  213.     CBrush* pOldBrush = NULL;
  214.     CGdiObject* pTemp;
  215.     int nOldROP;
  216.  
  217.     // draw lines
  218.     if ((m_nStyle & (dottedLine|solidLine)) != 0)
  219.     {
  220.         if (m_nStyle & dottedLine)
  221.             pOldPen = pDC->SelectObject(CPen::FromHandle(_afxBlackDottedPen));
  222.         else
  223.             pOldPen = (CPen*)pDC->SelectStockObject(BLACK_PEN);
  224.         pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
  225.         nOldROP = pDC->SetROP2(R2_COPYPEN);
  226.         rect.InflateRect(+1, +1);   // borders are one pixel outside
  227.         pDC->Rectangle(rect.left, rect.top, rect.right, rect.bottom);
  228.         pDC->SetROP2(nOldROP);
  229.     }
  230.  
  231. #if !defined(_WIN32_WCE)
  232.     // if hatchBrush is going to be used, need to unrealize it
  233.     if ((m_nStyle & (hatchInside|hatchedBorder)) != 0)
  234.         UnrealizeObject(_afxHatchBrush);
  235. #endif // _WIN32_WCE
  236.  
  237.     // hatch inside
  238.     if ((m_nStyle & hatchInside) != 0)
  239.     {
  240.         pTemp = pDC->SelectStockObject(NULL_PEN);
  241.         if (pOldPen == NULL)
  242.             pOldPen = (CPen*)pTemp;
  243.         pTemp = pDC->SelectObject(CBrush::FromHandle(_afxHatchBrush));
  244.         if (pOldBrush == NULL)
  245.             pOldBrush = (CBrush*)pTemp;
  246.         pDC->SetBkMode(TRANSPARENT);
  247.         nOldROP = pDC->SetROP2(R2_MASKNOTPEN);
  248.         pDC->Rectangle(rect.left+1, rect.top+1, rect.right, rect.bottom);
  249.         pDC->SetROP2(nOldROP);
  250.     }
  251.  
  252.     // draw hatched border
  253.     if ((m_nStyle & hatchedBorder) != 0)
  254.     {
  255.         pTemp = pDC->SelectObject(CBrush::FromHandle(_afxHatchBrush));
  256.         if (pOldBrush == NULL)
  257.             pOldBrush = (CBrush*)pTemp;
  258.         pDC->SetBkMode(OPAQUE);
  259.         CRect rectTrue;
  260.         GetTrueRect(&rectTrue);
  261.         pDC->PatBlt(rectTrue.left, rectTrue.top, rectTrue.Width(),
  262.             rect.top-rectTrue.top, 0x000F0001 /* Pn */);
  263.         pDC->PatBlt(rectTrue.left, rect.bottom,
  264.             rectTrue.Width(), rectTrue.bottom-rect.bottom, 0x000F0001 /* Pn */);
  265.         pDC->PatBlt(rectTrue.left, rect.top, rect.left-rectTrue.left,
  266.             rect.Height(), 0x000F0001 /* Pn */);
  267.         pDC->PatBlt(rect.right, rect.top, rectTrue.right-rect.right,
  268.             rect.Height(), 0x000F0001 /* Pn */);
  269.     }
  270.  
  271.     // draw resize handles
  272.     if ((m_nStyle & (resizeInside|resizeOutside)) != 0)
  273.     {
  274.         UINT mask = GetHandleMask();
  275.         for (int i = 0; i < 8; ++i)
  276.         {
  277.             if (mask & (1<<i))
  278.             {
  279.                 GetHandleRect((TrackerHit)i, &rect);
  280.                 pDC->FillSolidRect(rect, RGB(0, 0, 0));
  281.             }
  282.         }
  283.     }
  284.  
  285.     // cleanup pDC state
  286.     if (pOldPen != NULL)
  287.         pDC->SelectObject(pOldPen);
  288.     if (pOldBrush != NULL)
  289.         pDC->SelectObject(pOldBrush);
  290.     VERIFY(pDC->RestoreDC(-1));
  291. }
  292.  
  293. #if !defined(_WIN32_WCE_NO_CURSOR)
  294. BOOL CRectTracker::SetCursor(CWnd* pWnd, UINT nHitTest) const
  295. {
  296.     // trackers should only be in client area
  297.     if (nHitTest != HTCLIENT)
  298.         return FALSE;
  299.  
  300.     // convert cursor position to client co-ordinates
  301.     CPoint point;
  302.     WCE_FCTN(GetCursorPos)(&point);
  303.     pWnd->ScreenToClient(&point);
  304.  
  305.     // do hittest and normalize hit
  306.     int nHandle = HitTestHandles(point);
  307.     if (nHandle < 0)
  308.         return FALSE;
  309.  
  310.     // need to normalize the hittest such that we get proper cursors
  311.     nHandle = NormalizeHit(nHandle);
  312.  
  313.     // handle special case of hitting area between handles
  314.     //  (logically the same -- handled as a move -- but different cursor)
  315.     if (nHandle == hitMiddle && !m_rect.PtInRect(point))
  316.     {
  317.         // only for trackers with hatchedBorder (ie. in-place resizing)
  318.         if (m_nStyle & hatchedBorder)
  319.             nHandle = (TrackerHit)9;
  320.     }
  321.  
  322.     ASSERT(nHandle < _countof(_afxCursors));
  323.     ::SetCursor(_afxCursors[nHandle]);
  324.     return TRUE;
  325. }
  326. #endif // _WIN32_WCE_NO_CURSOR
  327.  
  328. int CRectTracker::HitTest(CPoint point) const
  329. {
  330.     TrackerHit hitResult = hitNothing;
  331.  
  332.     CRect rectTrue;
  333.     GetTrueRect(&rectTrue);
  334.     ASSERT(rectTrue.left <= rectTrue.right);
  335.     ASSERT(rectTrue.top <= rectTrue.bottom);
  336.     if (rectTrue.PtInRect(point))
  337.     {
  338.         if ((m_nStyle & (resizeInside|resizeOutside)) != 0)
  339.             hitResult = (TrackerHit)HitTestHandles(point);
  340.         else
  341.             hitResult = hitMiddle;
  342.     }
  343.     return hitResult;
  344. }
  345.  
  346. int CRectTracker::NormalizeHit(int nHandle) const
  347. {
  348.     ASSERT(nHandle <= 8 && nHandle >= -1);
  349.     if (nHandle == hitMiddle || nHandle == hitNothing)
  350.         return nHandle;
  351.     const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];
  352.     if (m_rect.Width() < 0)
  353.     {
  354.         nHandle = (TrackerHit)pHandleInfo->nInvertX;
  355.         pHandleInfo = &_afxHandleInfo[nHandle];
  356.     }
  357.     if (m_rect.Height() < 0)
  358.         nHandle = (TrackerHit)pHandleInfo->nInvertY;
  359.     return nHandle;
  360. }
  361.  
  362. BOOL CRectTracker::Track(CWnd* pWnd, CPoint point, BOOL bAllowInvert,
  363.     CWnd* pWndClipTo)
  364. {
  365.     // perform hit testing on the handles
  366.     int nHandle = HitTestHandles(point);
  367.     if (nHandle < 0)
  368.     {
  369.         // didn't hit a handle, so just return FALSE
  370.         return FALSE;
  371.     }
  372.  
  373.     // otherwise, call helper function to do the tracking
  374.     m_bAllowInvert = bAllowInvert;
  375.     return TrackHandle(nHandle, pWnd, point, pWndClipTo);
  376. }
  377.  
  378. BOOL CRectTracker::TrackRubberBand(CWnd* pWnd, CPoint point, BOOL bAllowInvert)
  379. {
  380.     // simply call helper function to track from bottom right handle
  381.     m_bAllowInvert = bAllowInvert;
  382.     m_rect.SetRect(point.x, point.y, point.x, point.y);
  383.     return TrackHandle(hitBottomRight, pWnd, point, NULL);
  384. }
  385.  
  386. void CRectTracker::DrawTrackerRect(
  387.     LPCRECT lpRect, CWnd* pWndClipTo, CDC* pDC, CWnd* pWnd)
  388. {
  389.     // first, normalize the rectangle for drawing
  390.     CRect rect = *lpRect;
  391.     rect.NormalizeRect();
  392.  
  393.     // convert to client coordinates
  394.     if (pWndClipTo != NULL)
  395.     {
  396.         pWnd->ClientToScreen(&rect);
  397.         pWndClipTo->ScreenToClient(&rect);
  398.     }
  399.  
  400.     CSize size(0, 0);
  401.     if (!m_bFinalErase)
  402.     {
  403.         // otherwise, size depends on the style
  404.         if (m_nStyle & hatchedBorder)
  405.         {
  406.             size.cx = size.cy = max(1, GetHandleSize(rect)-1);
  407.             rect.InflateRect(size);
  408.         }
  409.         else
  410.         {
  411.             size.cx = CX_BORDER;
  412.             size.cy = CY_BORDER;
  413.         }
  414.     }
  415.  
  416.     // and draw it
  417.     if (m_bFinalErase || !m_bErase)
  418.         pDC->DrawDragRect(rect, size, m_rectLast, m_sizeLast);
  419.  
  420.     // remember last rectangles
  421.     m_rectLast = rect;
  422.     m_sizeLast = size;
  423. }
  424.  
  425. void CRectTracker::AdjustRect(int nHandle, LPRECT)
  426. {
  427.     if (nHandle == hitMiddle)
  428.         return;
  429.  
  430.     // convert the handle into locations within m_rect
  431.     int *px, *py;
  432.     GetModifyPointers(nHandle, &px, &py, NULL, NULL);
  433.  
  434.     // enforce minimum width
  435.     int nNewWidth = m_rect.Width();
  436.     int nAbsWidth = m_bAllowInvert ? abs(nNewWidth) : nNewWidth;
  437.     if (px != NULL && nAbsWidth < m_sizeMin.cx)
  438.     {
  439.         nNewWidth = nAbsWidth != 0 ? nNewWidth / nAbsWidth : 1;
  440.         ASSERT((int*)px - (int*)&m_rect < _countof(_afxRectInfo));
  441.         const AFX_RECTINFO* pRectInfo = &_afxRectInfo[(int*)px - (int*)&m_rect];
  442.         *px = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +
  443.             nNewWidth * m_sizeMin.cx * -pRectInfo->nSignAcross;
  444.     }
  445.  
  446.     // enforce minimum height
  447.     int nNewHeight = m_rect.Height();
  448.     int nAbsHeight = m_bAllowInvert ? abs(nNewHeight) : nNewHeight;
  449.     if (py != NULL && nAbsHeight < m_sizeMin.cy)
  450.     {
  451.         nNewHeight = nAbsHeight != 0 ? nNewHeight / nAbsHeight : 1;
  452.         ASSERT((int*)py - (int*)&m_rect < _countof(_afxRectInfo));
  453.         const AFX_RECTINFO* pRectInfo = &_afxRectInfo[(int*)py - (int*)&m_rect];
  454.         *py = *(int*)((BYTE*)&m_rect + pRectInfo->nOffsetAcross) +
  455.             nNewHeight * m_sizeMin.cy * -pRectInfo->nSignAcross;
  456.     }
  457. }
  458.  
  459. void CRectTracker::GetTrueRect(LPRECT lpTrueRect) const
  460. {
  461.     ASSERT(AfxIsValidAddress(lpTrueRect, sizeof(RECT)));
  462.  
  463.     CRect rect = m_rect;
  464.     rect.NormalizeRect();
  465.     int nInflateBy = 0;
  466.     if ((m_nStyle & (resizeOutside|hatchedBorder)) != 0)
  467.         nInflateBy += GetHandleSize() - 1;
  468.     if ((m_nStyle & (solidLine|dottedLine)) != 0)
  469.         ++nInflateBy;
  470.     rect.InflateRect(nInflateBy, nInflateBy);
  471.     *lpTrueRect = rect;
  472. }
  473.  
  474. void CRectTracker::OnChangedRect(const CRect& /*rectOld*/)
  475. {
  476.     // no default implementation, useful for derived classes
  477. }
  478.  
  479. /////////////////////////////////////////////////////////////////////////////
  480. // CRectTracker implementation helpers
  481.  
  482. void CRectTracker::GetHandleRect(int nHandle, CRect* pHandleRect) const
  483. {
  484.     ASSERT(nHandle < 8);
  485.  
  486.     // get normalized rectangle of the tracker
  487.     CRect rectT = m_rect;
  488.     rectT.NormalizeRect();
  489.     if ((m_nStyle & (solidLine|dottedLine)) != 0)
  490.         rectT.InflateRect(+1, +1);
  491.  
  492.     // since the rectangle itself was normalized, we also have to invert the
  493.     //  resize handles.
  494.     nHandle = NormalizeHit(nHandle);
  495.  
  496.     // handle case of resize handles outside the tracker
  497.     int size = GetHandleSize();
  498.     if (m_nStyle & resizeOutside)
  499.         rectT.InflateRect(size-1, size-1);
  500.  
  501.     // calculate position of the resize handle
  502.     int nWidth = rectT.Width();
  503.     int nHeight = rectT.Height();
  504.     CRect rect;
  505.     const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];
  506.     rect.left = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetX);
  507.     rect.top = *(int*)((BYTE*)&rectT + pHandleInfo->nOffsetY);
  508.     rect.left += size * pHandleInfo->nHandleX;
  509.     rect.top += size * pHandleInfo->nHandleY;
  510.     rect.left += pHandleInfo->nCenterX * (nWidth - size) / 2;
  511.     rect.top += pHandleInfo->nCenterY * (nHeight - size) / 2;
  512.     rect.right = rect.left + size;
  513.     rect.bottom = rect.top + size;
  514.  
  515.     *pHandleRect = rect;
  516. }
  517.  
  518. int CRectTracker::GetHandleSize(LPCRECT lpRect) const
  519. {
  520.     if (lpRect == NULL)
  521.         lpRect = &m_rect;
  522.  
  523.     int size = m_nHandleSize;
  524.     if (!(m_nStyle & resizeOutside))
  525.     {
  526.         // make sure size is small enough for the size of the rect
  527.         int sizeMax = min(abs(lpRect->right - lpRect->left),
  528.             abs(lpRect->bottom - lpRect->top));
  529.         if (size * 2 > sizeMax)
  530.             size = sizeMax / 2;
  531.     }
  532.     return size;
  533. }
  534.  
  535. int CRectTracker::HitTestHandles(CPoint point) const
  536. {
  537.     CRect rect;
  538.     UINT mask = GetHandleMask();
  539.  
  540.     // see if hit anywhere inside the tracker
  541.     GetTrueRect(&rect);
  542.     if (!rect.PtInRect(point))
  543.         return hitNothing;  // totally missed
  544.  
  545.     // see if we hit a handle
  546.     for (int i = 0; i < 8; ++i)
  547.     {
  548.         if (mask & (1<<i))
  549.         {
  550.             GetHandleRect((TrackerHit)i, &rect);
  551.             if (rect.PtInRect(point))
  552.                 return (TrackerHit)i;
  553.         }
  554.     }
  555.  
  556.     // last of all, check for non-hit outside of object, between resize handles
  557.     if ((m_nStyle & hatchedBorder) == 0)
  558.     {
  559.         CRect rect = m_rect;
  560.         rect.NormalizeRect();
  561.         if ((m_nStyle & dottedLine|solidLine) != 0)
  562.             rect.InflateRect(+1, +1);
  563.         if (!rect.PtInRect(point))
  564.             return hitNothing;  // must have been between resize handles
  565.     }
  566.     return hitMiddle;   // no handle hit, but hit object (or object border)
  567. }
  568.  
  569. BOOL CRectTracker::TrackHandle(int nHandle, CWnd* pWnd, CPoint point,
  570.     CWnd* pWndClipTo)
  571. {
  572.     ASSERT(nHandle >= 0);
  573.     ASSERT(nHandle <= 8);   // handle 8 is inside the rect
  574.  
  575.     // don't handle if capture already set
  576.     if (::GetCapture() != NULL)
  577.         return FALSE;
  578.  
  579.     AfxLockTempMaps();  // protect maps while looping
  580.  
  581.     ASSERT(!m_bFinalErase);
  582.  
  583.     // save original width & height in pixels
  584.     int nWidth = m_rect.Width();
  585.     int nHeight = m_rect.Height();
  586.  
  587.     // set capture to the window which received this message
  588.     pWnd->SetCapture();
  589.     ASSERT(pWnd == CWnd::GetCapture());
  590.     pWnd->UpdateWindow();
  591.     if (pWndClipTo != NULL)
  592.         pWndClipTo->UpdateWindow();
  593.     CRect rectSave = m_rect;
  594.  
  595.     // find out what x/y coords we are supposed to modify
  596.     int *px, *py;
  597.     int xDiff, yDiff;
  598.     GetModifyPointers(nHandle, &px, &py, &xDiff, &yDiff);
  599.     xDiff = point.x - xDiff;
  600.     yDiff = point.y - yDiff;
  601.  
  602.     // get DC for drawing
  603.     CDC* pDrawDC;
  604.     if (pWndClipTo != NULL)
  605.     {
  606.         // clip to arbitrary window by using adjusted Window DC
  607.         pDrawDC = pWndClipTo->WCE_IF(GetDC(),GetDCEx(NULL, DCX_CACHE));
  608.     }
  609.     else
  610.     {
  611.         // otherwise, just use normal DC
  612.         pDrawDC = pWnd->GetDC();
  613.     }
  614.     ASSERT_VALID(pDrawDC);
  615.  
  616.     CRect rectOld;
  617.     BOOL bMoved = FALSE;
  618.  
  619.     // get messages until capture lost or cancelled/accepted
  620.     for (;;)
  621.     {
  622.         MSG msg;
  623.         VERIFY(::GetMessage(&msg, NULL, 0, 0));
  624.  
  625.         if (CWnd::GetCapture() != pWnd)
  626.             break;
  627.  
  628.         switch (msg.message)
  629.         {
  630.         // handle movement/accept messages
  631.         case WM_LBUTTONUP:
  632.         case WM_MOUSEMOVE:
  633.             rectOld = m_rect;
  634.             // handle resize cases (and part of move)
  635.             if (px != NULL)
  636.                 *px = (int)(short)LOWORD(msg.lParam) - xDiff;
  637.             if (py != NULL)
  638.                 *py = (int)(short)HIWORD(msg.lParam) - yDiff;
  639.  
  640.             // handle move case
  641.             if (nHandle == hitMiddle)
  642.             {
  643.                 m_rect.right = m_rect.left + nWidth;
  644.                 m_rect.bottom = m_rect.top + nHeight;
  645.             }
  646.             // allow caller to adjust the rectangle if necessary
  647.             AdjustRect(nHandle, &m_rect);
  648.  
  649.             // only redraw and callback if the rect actually changed!
  650.             m_bFinalErase = (msg.message == WM_LBUTTONUP);
  651.             if (!rectOld.EqualRect(&m_rect) || m_bFinalErase)
  652.             {
  653.                 if (bMoved)
  654.                 {
  655.                     m_bErase = TRUE;
  656.                     DrawTrackerRect(&rectOld, pWndClipTo, pDrawDC, pWnd);
  657.                 }
  658.                 OnChangedRect(rectOld);
  659.                 if (msg.message != WM_LBUTTONUP)
  660.                     bMoved = TRUE;
  661.             }
  662.             if (m_bFinalErase)
  663.                 goto ExitLoop;
  664.  
  665.             if (!rectOld.EqualRect(&m_rect))
  666.             {
  667.                 m_bErase = FALSE;
  668.                 DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd);
  669.             }
  670.             break;
  671.  
  672.         // handle cancel messages
  673.         case WM_KEYDOWN:
  674.             if (msg.wParam != VK_ESCAPE)
  675.                 break;
  676.         case WM_RBUTTONDOWN:
  677.             if (bMoved)
  678.             {
  679.                 m_bErase = m_bFinalErase = TRUE;
  680.                 DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd);
  681.             }
  682.             m_rect = rectSave;
  683.             goto ExitLoop;
  684.  
  685.         // just dispatch rest of the messages
  686.         default:
  687.             DispatchMessage(&msg);
  688.             break;
  689.         }
  690.     }
  691.  
  692. ExitLoop:
  693.     if (pWndClipTo != NULL)
  694.         pWndClipTo->ReleaseDC(pDrawDC);
  695.     else
  696.         pWnd->ReleaseDC(pDrawDC);
  697.     ReleaseCapture();
  698.  
  699.     AfxUnlockTempMaps(FALSE);
  700.  
  701.     // restore rect in case bMoved is still FALSE
  702.     if (!bMoved)
  703.         m_rect = rectSave;
  704.     m_bFinalErase = FALSE;
  705.     m_bErase = FALSE;
  706.  
  707.     // return TRUE only if rect has changed
  708.     return !rectSave.EqualRect(&m_rect);
  709. }
  710.  
  711. void CRectTracker::GetModifyPointers(
  712.     int nHandle, int** ppx, int** ppy, int* px, int* py)
  713. {
  714.     ASSERT(nHandle >= 0);
  715.     ASSERT(nHandle <= 8);
  716.  
  717.     if (nHandle == hitMiddle)
  718.         nHandle = hitTopLeft;   // same as hitting top-left
  719.  
  720.     *ppx = NULL;
  721.     *ppy = NULL;
  722.  
  723.     // fill in the part of the rect that this handle modifies
  724.     //  (Note: handles that map to themselves along a given axis when that
  725.     //   axis is inverted don't modify the value on that axis)
  726.  
  727.     const AFX_HANDLEINFO* pHandleInfo = &_afxHandleInfo[nHandle];
  728.     if (pHandleInfo->nInvertX != nHandle)
  729.     {
  730.         *ppx = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetX);
  731.         if (px != NULL)
  732.             *px = **ppx;
  733.     }
  734.     else
  735.     {
  736.         // middle handle on X axis
  737.         if (px != NULL)
  738.             *px = m_rect.left + abs(m_rect.Width()) / 2;
  739.     }
  740.     if (pHandleInfo->nInvertY != nHandle)
  741.     {
  742.         *ppy = (int*)((BYTE*)&m_rect + pHandleInfo->nOffsetY);
  743.         if (py != NULL)
  744.             *py = **ppy;
  745.     }
  746.     else
  747.     {
  748.         // middle handle on Y axis
  749.         if (py != NULL)
  750.             *py = m_rect.top + abs(m_rect.Height()) / 2;
  751.     }
  752. }
  753.  
  754. UINT CRectTracker::GetHandleMask() const
  755. {
  756.     UINT mask = 0x0F;   // always have 4 corner handles
  757.     int size = m_nHandleSize*3;
  758.     if (abs(m_rect.Width()) - size > 4)
  759.         mask |= 0x50;
  760.     if (abs(m_rect.Height()) - size > 4)
  761.         mask |= 0xA0;
  762.     return mask;
  763. }
  764.  
  765. /////////////////////////////////////////////////////////////////////////////
  766.